{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/run-llama/llama_index/blob/main/docs/examples/cookbooks/mongodb_retrieval_strategies.ipynb)\n",
    "\n",
    "[![View Article](https://img.shields.io/badge/View%20Article-blue)](https://www.mongodb.com/developer/products/atlas/optimize-relevance-mongodb-llamaindex/?utm_campaign=devrel&utm_source=cross-post&utm_medium=organic_social&utm_content=https%3A%2F%2Fgithub.com%2Fmongodb-developer%2FGenAI-Showcase&utm_term=apoorva.joshi)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Optimizing for relevance using MongoDB and LlamaIndex\n",
    "\n",
    "In this notebook, we will explore and tune different retrieval options in MongoDB's LlamaIndex integration to get the most relevant results."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 1: Install libraries\n",
    "\n",
    "- **pymongo**: Python package to interact with MongoDB databases and collections\n",
    "<p>\n",
    "- **llama-index**: Python package for the LlamaIndex LLM framework\n",
    "<p>\n",
    "- **llama-index-llms-openai**: Python package to use OpenAI models via their LlamaIndex integration \n",
    "<p>\n",
    "- **llama-index-vector-stores-mongodb**: Python package for MongoDB’s LlamaIndex integration "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.2.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.2\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "!pip install -qU pymongo llama-index llama-index-llms-openai llama-index-vector-stores-mongodb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2: Setup prerequisites\n",
    "\n",
    "- **Set the MongoDB connection string**: Follow the steps [here](https://www.mongodb.com/docs/manual/reference/connection-string/) to get the connection string from the Atlas UI.\n",
    "\n",
    "- **Set the OpenAI API key**: Steps to obtain an API key as [here](https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import getpass\n",
    "from pymongo import MongoClient"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "os.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"Enter your OpenAI API key: \")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "MONGODB_URI = getpass.getpass(\"Enter your MongoDB URI: \")\n",
    "mongodb_client = MongoClient(\n",
    "    MONGODB_URI, appname=\"devrel.content.retrieval_strategies_llamaindex\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3: Load and process the dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datasets import load_dataset\n",
    "import pandas as pd\n",
    "from llama_index.core import Document"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = load_dataset(\"MongoDB/embedded_movies\", split=\"train\")\n",
    "data = pd.DataFrame(data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>plot</th>\n",
       "      <th>runtime</th>\n",
       "      <th>genres</th>\n",
       "      <th>fullplot</th>\n",
       "      <th>directors</th>\n",
       "      <th>writers</th>\n",
       "      <th>countries</th>\n",
       "      <th>poster</th>\n",
       "      <th>languages</th>\n",
       "      <th>cast</th>\n",
       "      <th>title</th>\n",
       "      <th>num_mflix_comments</th>\n",
       "      <th>rated</th>\n",
       "      <th>imdb</th>\n",
       "      <th>awards</th>\n",
       "      <th>type</th>\n",
       "      <th>metacritic</th>\n",
       "      <th>plot_embedding</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Young Pauline is left a lot of money when her ...</td>\n",
       "      <td>199.0</td>\n",
       "      <td>[Action]</td>\n",
       "      <td>Young Pauline is left a lot of money when her ...</td>\n",
       "      <td>[Louis J. Gasnier, Donald MacKenzie]</td>\n",
       "      <td>[Charles W. Goddard (screenplay), Basil Dickey...</td>\n",
       "      <td>[USA]</td>\n",
       "      <td>https://m.media-amazon.com/images/M/MV5BMzgxOD...</td>\n",
       "      <td>[English]</td>\n",
       "      <td>[Pearl White, Crane Wilbur, Paul Panzer, Edwar...</td>\n",
       "      <td>The Perils of Pauline</td>\n",
       "      <td>0</td>\n",
       "      <td>None</td>\n",
       "      <td>{'id': 4465, 'rating': 7.6, 'votes': 744}</td>\n",
       "      <td>{'nominations': 0, 'text': '1 win.', 'wins': 1}</td>\n",
       "      <td>movie</td>\n",
       "      <td>NaN</td>\n",
       "      <td>[0.0007293965299999999, -0.026834568000000003,...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>A penniless young man tries to save an heiress...</td>\n",
       "      <td>22.0</td>\n",
       "      <td>[Comedy, Short, Action]</td>\n",
       "      <td>As a penniless man worries about how he will m...</td>\n",
       "      <td>[Alfred J. Goulding, Hal Roach]</td>\n",
       "      <td>[H.M. Walker (titles)]</td>\n",
       "      <td>[USA]</td>\n",
       "      <td>https://m.media-amazon.com/images/M/MV5BNzE1OW...</td>\n",
       "      <td>[English]</td>\n",
       "      <td>[Harold Lloyd, Mildred Davis, 'Snub' Pollard, ...</td>\n",
       "      <td>From Hand to Mouth</td>\n",
       "      <td>0</td>\n",
       "      <td>TV-G</td>\n",
       "      <td>{'id': 10146, 'rating': 7.0, 'votes': 639}</td>\n",
       "      <td>{'nominations': 1, 'text': '1 nomination.', 'w...</td>\n",
       "      <td>movie</td>\n",
       "      <td>NaN</td>\n",
       "      <td>[-0.022837115, -0.022941574000000003, 0.014937...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Michael \"Beau\" Geste leaves England in disgrac...</td>\n",
       "      <td>101.0</td>\n",
       "      <td>[Action, Adventure, Drama]</td>\n",
       "      <td>Michael \"Beau\" Geste leaves England in disgrac...</td>\n",
       "      <td>[Herbert Brenon]</td>\n",
       "      <td>[Herbert Brenon (adaptation), John Russell (ad...</td>\n",
       "      <td>[USA]</td>\n",
       "      <td>None</td>\n",
       "      <td>[English]</td>\n",
       "      <td>[Ronald Colman, Neil Hamilton, Ralph Forbes, A...</td>\n",
       "      <td>Beau Geste</td>\n",
       "      <td>0</td>\n",
       "      <td>None</td>\n",
       "      <td>{'id': 16634, 'rating': 6.9, 'votes': 222}</td>\n",
       "      <td>{'nominations': 0, 'text': '1 win.', 'wins': 1}</td>\n",
       "      <td>movie</td>\n",
       "      <td>NaN</td>\n",
       "      <td>[0.00023330492999999998, -0.028511643000000003...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Seeking revenge, an athletic young man joins t...</td>\n",
       "      <td>88.0</td>\n",
       "      <td>[Adventure, Action]</td>\n",
       "      <td>A nobleman vows to avenge the death of his fat...</td>\n",
       "      <td>[Albert Parker]</td>\n",
       "      <td>[Douglas Fairbanks (story), Jack Cunningham (a...</td>\n",
       "      <td>[USA]</td>\n",
       "      <td>https://m.media-amazon.com/images/M/MV5BMzU0ND...</td>\n",
       "      <td>None</td>\n",
       "      <td>[Billie Dove, Tempe Pigott, Donald Crisp, Sam ...</td>\n",
       "      <td>The Black Pirate</td>\n",
       "      <td>1</td>\n",
       "      <td>None</td>\n",
       "      <td>{'id': 16654, 'rating': 7.2, 'votes': 1146}</td>\n",
       "      <td>{'nominations': 0, 'text': '1 win.', 'wins': 1}</td>\n",
       "      <td>movie</td>\n",
       "      <td>NaN</td>\n",
       "      <td>[-0.005927917, -0.033394486, 0.0015323418, -0....</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>An irresponsible young millionaire changes his...</td>\n",
       "      <td>58.0</td>\n",
       "      <td>[Action, Comedy, Romance]</td>\n",
       "      <td>The Uptown Boy, J. Harold Manners (Lloyd) is a...</td>\n",
       "      <td>[Sam Taylor]</td>\n",
       "      <td>[Ted Wilde (story), John Grey (story), Clyde B...</td>\n",
       "      <td>[USA]</td>\n",
       "      <td>https://m.media-amazon.com/images/M/MV5BMTcxMT...</td>\n",
       "      <td>[English]</td>\n",
       "      <td>[Harold Lloyd, Jobyna Ralston, Noah Young, Jim...</td>\n",
       "      <td>For Heaven's Sake</td>\n",
       "      <td>0</td>\n",
       "      <td>PASSED</td>\n",
       "      <td>{'id': 16895, 'rating': 7.6, 'votes': 918}</td>\n",
       "      <td>{'nominations': 1, 'text': '1 nomination.', 'w...</td>\n",
       "      <td>movie</td>\n",
       "      <td>NaN</td>\n",
       "      <td>[-0.0059373598, -0.026604708, -0.0070914757000...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                plot  runtime  \\\n",
       "0  Young Pauline is left a lot of money when her ...    199.0   \n",
       "1  A penniless young man tries to save an heiress...     22.0   \n",
       "2  Michael \"Beau\" Geste leaves England in disgrac...    101.0   \n",
       "3  Seeking revenge, an athletic young man joins t...     88.0   \n",
       "4  An irresponsible young millionaire changes his...     58.0   \n",
       "\n",
       "                       genres  \\\n",
       "0                    [Action]   \n",
       "1     [Comedy, Short, Action]   \n",
       "2  [Action, Adventure, Drama]   \n",
       "3         [Adventure, Action]   \n",
       "4   [Action, Comedy, Romance]   \n",
       "\n",
       "                                            fullplot  \\\n",
       "0  Young Pauline is left a lot of money when her ...   \n",
       "1  As a penniless man worries about how he will m...   \n",
       "2  Michael \"Beau\" Geste leaves England in disgrac...   \n",
       "3  A nobleman vows to avenge the death of his fat...   \n",
       "4  The Uptown Boy, J. Harold Manners (Lloyd) is a...   \n",
       "\n",
       "                              directors  \\\n",
       "0  [Louis J. Gasnier, Donald MacKenzie]   \n",
       "1       [Alfred J. Goulding, Hal Roach]   \n",
       "2                      [Herbert Brenon]   \n",
       "3                       [Albert Parker]   \n",
       "4                          [Sam Taylor]   \n",
       "\n",
       "                                             writers countries  \\\n",
       "0  [Charles W. Goddard (screenplay), Basil Dickey...     [USA]   \n",
       "1                             [H.M. Walker (titles)]     [USA]   \n",
       "2  [Herbert Brenon (adaptation), John Russell (ad...     [USA]   \n",
       "3  [Douglas Fairbanks (story), Jack Cunningham (a...     [USA]   \n",
       "4  [Ted Wilde (story), John Grey (story), Clyde B...     [USA]   \n",
       "\n",
       "                                              poster  languages  \\\n",
       "0  https://m.media-amazon.com/images/M/MV5BMzgxOD...  [English]   \n",
       "1  https://m.media-amazon.com/images/M/MV5BNzE1OW...  [English]   \n",
       "2                                               None  [English]   \n",
       "3  https://m.media-amazon.com/images/M/MV5BMzU0ND...       None   \n",
       "4  https://m.media-amazon.com/images/M/MV5BMTcxMT...  [English]   \n",
       "\n",
       "                                                cast                  title  \\\n",
       "0  [Pearl White, Crane Wilbur, Paul Panzer, Edwar...  The Perils of Pauline   \n",
       "1  [Harold Lloyd, Mildred Davis, 'Snub' Pollard, ...     From Hand to Mouth   \n",
       "2  [Ronald Colman, Neil Hamilton, Ralph Forbes, A...             Beau Geste   \n",
       "3  [Billie Dove, Tempe Pigott, Donald Crisp, Sam ...       The Black Pirate   \n",
       "4  [Harold Lloyd, Jobyna Ralston, Noah Young, Jim...      For Heaven's Sake   \n",
       "\n",
       "   num_mflix_comments   rated                                         imdb  \\\n",
       "0                   0    None    {'id': 4465, 'rating': 7.6, 'votes': 744}   \n",
       "1                   0    TV-G   {'id': 10146, 'rating': 7.0, 'votes': 639}   \n",
       "2                   0    None   {'id': 16634, 'rating': 6.9, 'votes': 222}   \n",
       "3                   1    None  {'id': 16654, 'rating': 7.2, 'votes': 1146}   \n",
       "4                   0  PASSED   {'id': 16895, 'rating': 7.6, 'votes': 918}   \n",
       "\n",
       "                                              awards   type  metacritic  \\\n",
       "0    {'nominations': 0, 'text': '1 win.', 'wins': 1}  movie         NaN   \n",
       "1  {'nominations': 1, 'text': '1 nomination.', 'w...  movie         NaN   \n",
       "2    {'nominations': 0, 'text': '1 win.', 'wins': 1}  movie         NaN   \n",
       "3    {'nominations': 0, 'text': '1 win.', 'wins': 1}  movie         NaN   \n",
       "4  {'nominations': 1, 'text': '1 nomination.', 'w...  movie         NaN   \n",
       "\n",
       "                                      plot_embedding  \n",
       "0  [0.0007293965299999999, -0.026834568000000003,...  \n",
       "1  [-0.022837115, -0.022941574000000003, 0.014937...  \n",
       "2  [0.00023330492999999998, -0.028511643000000003...  \n",
       "3  [-0.005927917, -0.033394486, 0.0015323418, -0....  \n",
       "4  [-0.0059373598, -0.026604708, -0.0070914757000...  "
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Fill Nones in the dataframe\n",
    "data = data.fillna(\n",
    "    {\"genres\": \"[]\", \"languages\": \"[]\", \"cast\": \"[]\", \"imdb\": \"{}\"}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "documents = []\n",
    "\n",
    "for _, row in data.iterrows():\n",
    "    # Extract required fields\n",
    "    title = row[\"title\"]\n",
    "    rating = row[\"imdb\"].get(\"rating\", 0)\n",
    "    languages = row[\"languages\"]\n",
    "    cast = row[\"cast\"]\n",
    "    genres = row[\"genres\"]\n",
    "    # Create the metadata attribute\n",
    "    metadata = {\"title\": title, \"rating\": rating, \"languages\": languages}\n",
    "    # Create the text attribute\n",
    "    text = f\"Title: {title}\\nPlot: {row['fullplot']}\\nCast: {', '.join(item for item in cast)}\\nGenres: {', '.join(item for item in  genres)}\\nLanguages: {', '.join(item for item in languages)}\\nRating: {rating}\"\n",
    "    documents.append(Document(text=text, metadata=metadata))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title: The Perils of Pauline\n",
      "Plot: Young Pauline is left a lot of money when her wealthy uncle dies. However, her uncle's secretary has been named as her guardian until she marries, at which time she will officially take possession of her inheritance. Meanwhile, her \"guardian\" and his confederates constantly come up with schemes to get rid of Pauline so that he can get his hands on the money himself.\n",
      "Cast: Pearl White, Crane Wilbur, Paul Panzer, Edward Josè\n",
      "Genres: Action\n",
      "Languages: English\n",
      "Rating: 7.6\n"
     ]
    }
   ],
   "source": [
    "print(documents[0].text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'title': 'The Perils of Pauline', 'rating': 7.6, 'languages': ['English']}\n"
     ]
    }
   ],
   "source": [
    "print(documents[0].metadata)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 4: Create MongoDB Atlas vector store"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from llama_index.embeddings.openai import OpenAIEmbedding\n",
    "from llama_index.vector_stores.mongodb import MongoDBAtlasVectorSearch\n",
    "from llama_index.core.settings import Settings\n",
    "from llama_index.core import VectorStoreIndex, StorageContext\n",
    "from pymongo.operations import SearchIndexModel\n",
    "from pymongo.errors import OperationFailure"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Settings.embed_model = OpenAIEmbedding(model=\"text-embedding-3-small\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "VS_INDEX_NAME = \"vector_index\"\n",
    "FTS_INDEX_NAME = \"fts_index\"\n",
    "DB_NAME = \"llamaindex\"\n",
    "COLLECTION_NAME = \"hybrid_search\"\n",
    "collection = mongodb_client[DB_NAME][COLLECTION_NAME]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vector_store = MongoDBAtlasVectorSearch(\n",
    "    mongodb_client,\n",
    "    db_name=DB_NAME,\n",
    "    collection_name=COLLECTION_NAME,\n",
    "    vector_index_name=VS_INDEX_NAME,\n",
    "    fulltext_index_name=FTS_INDEX_NAME,\n",
    "    embedding_key=\"embedding\",\n",
    "    text_key=\"text\",\n",
    ")\n",
    "# If the collection has documents with embeddings already, create the vector store index from the vector store\n",
    "if collection.count_documents({}) > 0:\n",
    "    vector_store_index = VectorStoreIndex.from_vector_store(vector_store)\n",
    "# If the collection does not have documents, embed and ingest them into the vector store\n",
    "else:\n",
    "    vector_store_context = StorageContext.from_defaults(\n",
    "        vector_store=vector_store\n",
    "    )\n",
    "    vector_store_index = VectorStoreIndex.from_documents(\n",
    "        documents, storage_context=vector_store_context, show_progress=True\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5: Create Atlas Search indexes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vs_model = SearchIndexModel(\n",
    "    definition={\n",
    "        \"fields\": [\n",
    "            {\n",
    "                \"type\": \"vector\",\n",
    "                \"path\": \"embedding\",\n",
    "                \"numDimensions\": 1536,\n",
    "                \"similarity\": \"cosine\",\n",
    "            },\n",
    "            {\"type\": \"filter\", \"path\": \"metadata.rating\"},\n",
    "            {\"type\": \"filter\", \"path\": \"metadata.language\"},\n",
    "        ]\n",
    "    },\n",
    "    name=VS_INDEX_NAME,\n",
    "    type=\"vectorSearch\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fts_model = SearchIndexModel(\n",
    "    definition={\n",
    "        \"mappings\": {\"dynamic\": False, \"fields\": {\"text\": {\"type\": \"string\"}}}\n",
    "    },\n",
    "    name=FTS_INDEX_NAME,\n",
    "    type=\"search\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Duplicate index found for model <pymongo.operations.SearchIndexModel object at 0x31d4c33d0>. Skipping index creation.\n",
      "Duplicate index found for model <pymongo.operations.SearchIndexModel object at 0x31d4c1c60>. Skipping index creation.\n"
     ]
    }
   ],
   "source": [
    "for model in [vs_model, fts_model]:\n",
    "    try:\n",
    "        collection.create_search_index(model=model)\n",
    "    except OperationFailure:\n",
    "        print(\n",
    "            f\"Duplicate index found for model {model}. Skipping index creation.\"\n",
    "        )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 6: Get movie recommendations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_recommendations(query: str, mode: str, **kwargs) -> None:\n",
    "    \"\"\"\n",
    "    Get movie recommendations\n",
    "\n",
    "    Args:\n",
    "        query (str): User query\n",
    "        mode (str): Retrieval mode. One of (default, text_search, hybrid)\n",
    "    \"\"\"\n",
    "    query_engine = vector_store_index.as_query_engine(\n",
    "        similarity_top_k=5, vector_store_query_mode=mode, **kwargs\n",
    "    )\n",
    "    response = query_engine.query(query)\n",
    "    nodes = response.source_nodes\n",
    "    for node in nodes:\n",
    "        title = node.metadata[\"title\"]\n",
    "        rating = node.metadata[\"rating\"]\n",
    "        score = node.score\n",
    "        print(f\"Title: {title} | Rating: {rating} | Relevance Score: {score}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Full-text search"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title: Hellboy II: The Golden Army | Rating: 7.0 | Relevance Score: 5.93734884262085\n",
      "Title: The Matrix Revolutions | Rating: 6.7 | Relevance Score: 4.574477195739746\n",
      "Title: The Matrix | Rating: 8.7 | Relevance Score: 4.387373924255371\n",
      "Title: Go with Peace Jamil | Rating: 6.9 | Relevance Score: 3.5394840240478516\n",
      "Title: Terminator Salvation | Rating: 6.7 | Relevance Score: 3.3378987312316895\n"
     ]
    }
   ],
   "source": [
    "get_recommendations(\n",
    "    query=\"Action movies about humans fighting machines\",\n",
    "    mode=\"text_search\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Vector search"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title: Death Machine | Rating: 5.7 | Relevance Score: 0.7407287359237671\n",
      "Title: Real Steel | Rating: 7.1 | Relevance Score: 0.7364246845245361\n",
      "Title: Soldier | Rating: 5.9 | Relevance Score: 0.7282171249389648\n",
      "Title: Terminator 3: Rise of the Machines | Rating: 6.4 | Relevance Score: 0.7266112565994263\n",
      "Title: Last Action Hero | Rating: 6.2 | Relevance Score: 0.7250100374221802\n"
     ]
    }
   ],
   "source": [
    "get_recommendations(\n",
    "    query=\"Action movies about humans fighting machines\", mode=\"default\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Hybrid search"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title: Hellboy II: The Golden Army | Rating: 7.0 | Relevance Score: 0.5\n",
      "Title: Death Machine | Rating: 5.7 | Relevance Score: 0.5\n",
      "Title: The Matrix Revolutions | Rating: 6.7 | Relevance Score: 0.25\n",
      "Title: Real Steel | Rating: 7.1 | Relevance Score: 0.25\n",
      "Title: Soldier | Rating: 5.9 | Relevance Score: 0.16666666666666666\n"
     ]
    }
   ],
   "source": [
    "# Vector and full-text search weighted equal by default\n",
    "get_recommendations(\n",
    "    query=\"Action movies about humans fighting machines\", mode=\"hybrid\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title: Death Machine | Rating: 5.7 | Relevance Score: 0.7\n",
      "Title: Real Steel | Rating: 7.1 | Relevance Score: 0.35\n",
      "Title: Hellboy II: The Golden Army | Rating: 7.0 | Relevance Score: 0.30000000000000004\n",
      "Title: Soldier | Rating: 5.9 | Relevance Score: 0.2333333333333333\n",
      "Title: Terminator 3: Rise of the Machines | Rating: 6.4 | Relevance Score: 0.175\n"
     ]
    }
   ],
   "source": [
    "# Higher alpha, vector search dominates\n",
    "get_recommendations(\n",
    "    query=\"Action movies about humans fighting machines\",\n",
    "    mode=\"hybrid\",\n",
    "    alpha=0.7,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title: Hellboy II: The Golden Army | Rating: 7.0 | Relevance Score: 0.7\n",
      "Title: The Matrix Revolutions | Rating: 6.7 | Relevance Score: 0.35\n",
      "Title: Death Machine | Rating: 5.7 | Relevance Score: 0.3\n",
      "Title: The Matrix | Rating: 8.7 | Relevance Score: 0.2333333333333333\n",
      "Title: Go with Peace Jamil | Rating: 6.9 | Relevance Score: 0.175\n"
     ]
    }
   ],
   "source": [
    "# Lower alpha, full-text search dominates\n",
    "get_recommendations(\n",
    "    query=\"Action movies about humans fighting machines\",\n",
    "    mode=\"hybrid\",\n",
    "    alpha=0.3,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Combining metadata filters with search"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from llama_index.core.vector_stores import (\n",
    "    MetadataFilter,\n",
    "    MetadataFilters,\n",
    "    FilterOperator,\n",
    "    FilterCondition,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "filters = MetadataFilters(\n",
    "    filters=[\n",
    "        MetadataFilter(\n",
    "            key=\"metadata.rating\", value=7, operator=FilterOperator.GT\n",
    "        ),\n",
    "        MetadataFilter(\n",
    "            key=\"metadata.languages\",\n",
    "            value=\"English\",\n",
    "            operator=FilterOperator.EQ,\n",
    "        ),\n",
    "    ],\n",
    "    condition=FilterCondition.AND,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title: Real Steel | Rating: 7.1 | Relevance Score: 0.7\n",
      "Title: T2 3-D: Battle Across Time | Rating: 7.8 | Relevance Score: 0.35\n",
      "Title: The Matrix | Rating: 8.7 | Relevance Score: 0.30000000000000004\n",
      "Title: Predator | Rating: 7.8 | Relevance Score: 0.2333333333333333\n",
      "Title: Transformers | Rating: 7.1 | Relevance Score: 0.175\n"
     ]
    }
   ],
   "source": [
    "get_recommendations(\n",
    "    query=\"Action movies about humans fighting machines\",\n",
    "    mode=\"hybrid\",\n",
    "    alpha=0.7,\n",
    "    filters=filters,\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "provenance": [],
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
